//@version=6
indicator("3 Candle FVG with 5m S/R", overlay=true, max_boxes_count=500, max_lines_count=500)

// ===== Input Settings =====
// EMA Settings
emaLength = input.int(50, "EMA Length", minval=1)
emaColor = input.color(color.yellow, "EMA Color")
emaWidth = input.int(2, "EMA Line Width", minval=1, maxval=5)

// Signal Settings
showBullishSignals = input.bool(true, "Show Bullish Signals")
showBearishSignals = input.bool(true, "Show Bearish Signals")
bullishSignalColor = input.color(color.new(color.green, 0), "Bullish Signal Color")
bearishSignalColor = input.color(color.new(color.red, 0), "Bearish Signal Color")
bullishSignalShape = input.string("Triangle Up", "Bullish Signal Shape", options=["Triangle Up", "Arrow Up", "Circle", "Cross", "Diamond", "Square"])
bearishSignalShape = input.string("Triangle Down", "Bearish Signal Shape", options=["Triangle Down", "Arrow Down", "Circle", "Cross", "Diamond", "Square"])

// Entry Signal 1 Settings (Crosses EMA)
showEntrySignals = input.bool(true, "Show Entry 1 (Crosses EMA)")
entryFlagSize = input.string("large", "Entry 1 Flag Size", options=["tiny", "small", "normal", "large", "huge"])
entryFlagColor = input.color(color.new(color.blue, 0), "Entry 1 Flag Color")
showStopLoss = input.bool(true, "Show Stop Loss Lines")
entryLineExtend = input.int(10, "Entry 1 Line Extension (bars)", minval=5, maxval=50)

// Entry Signal 2 Settings (Does NOT Cross EMA)
showEntrySignals2 = input.bool(true, "Show Entry 2 (No EMA Cross)")
entry2FlagSize = input.string("large", "Entry 2 Flag Size", options=["tiny", "small", "normal", "large", "huge"])
entry2FlagColor = input.color(color.new(color.purple, 0), "Entry 2 Flag Color")
showStopLoss2 = input.bool(true, "Show Entry 2 Stop Loss Lines")
entry2LineExtend = input.int(10, "Entry 2 Line Extension (bars)", minval=5, maxval=50)

// FVG Box Settings
showFVGBoxes = input.bool(true, "Show FVG Boxes")
fvgBullishColor = input.color(color.new(color.green, 80), "Bullish FVG Box Color")
fvgBearishColor = input.color(color.new(color.red, 80), "Bearish FVG Box Color")
fvgBoxExtension = input.int(20, "FVG Box Extension (bars)", minval=1, maxval=100)

// Engulfing Candle Settings
showEngulfing = input.bool(true, "Show Engulfing Labels")
bullishEngulfingColor = input.color(color.new(color.lime, 0), "Bullish Engulfing Color")
bearishEngulfingColor = input.color(color.new(color.fuchsia, 0), "Bearish Engulfing Color")
engulfingLabelSize = input.string("small", "Engulfing Label Size", options=["tiny", "small", "normal", "large"])

// 5-Minute Support & Resistance Settings
showSR = input.bool(true, "Show 5m Support & Resistance")
srLookback = input.int(10, "5m S/R Lookback Period", minval=5, maxval=100)
srHistoryBars = input.int(200, "Look Back History (bars)", minval=50, maxval=500, tooltip="How far back to search for S/R levels")
supportColor = input.color(color.new(color.green, 30), "Support Color")
resistanceColor = input.color(color.new(color.red, 30), "Resistance Color")
showNearestOnly = input.bool(true, "Show Only 5 Nearest S/R Levels")

// ===== Calculate 50 EMA =====
ema50 = ta.ema(close, emaLength)
plot(ema50, "EMA", color=emaColor, linewidth=emaWidth)

// ===== Helper Functions =====
isBullish(index) =>
    close[index] > open[index]

isBearish(index) =>
    close[index] < open[index]

threeConsecutiveBullish() =>
    isBullish(0) and isBullish(1) and isBullish(2)

threeConsecutiveBearish() =>
    isBearish(0) and isBearish(1) and isBearish(2)

bullishFVG() =>
    low[0] > high[2]

bearishFVG() =>
    high[0] < low[2]

candlesInteractWithEMA() =>
    (low[0] <= ema50[0] and high[0] >= ema50[0]) or (low[1] <= ema50[1] and high[1] >= ema50[1]) or (low[2] <= ema50[2] and high[2] >= ema50[2])

candlesDoNotInteractWithEMA() =>
    not ((low[0] <= ema50[0] and high[0] >= ema50[0]) or (low[1] <= ema50[1] and high[1] >= ema50[1]) or (low[2] <= ema50[2] and high[2] >= ema50[2]))

// Engulfing Candle Detection
bullishEngulfing() =>
    isBearish(1) and isBullish(0) and open <= close[1] and close >= open[1]

bearishEngulfing() =>
    isBullish(1) and isBearish(0) and open >= close[1] and close <= open[1]

// Shape selector helper
getBullishShape() =>
    bullishSignalShape == "Triangle Up" ? shape.triangleup : bullishSignalShape == "Arrow Up" ? shape.arrowup : bullishSignalShape == "Circle" ? shape.circle : bullishSignalShape == "Cross" ? shape.cross : bullishSignalShape == "Diamond" ? shape.diamond : shape.square

getBearishShape() =>
    bearishSignalShape == "Triangle Down" ? shape.triangledown : bearishSignalShape == "Arrow Down" ? shape.arrowdown : bearishSignalShape == "Circle" ? shape.circle : bearishSignalShape == "Cross" ? shape.cross : bearishSignalShape == "Diamond" ? shape.diamond : shape.square

// Size selector helpers
getEntryFlagSize() =>
    entryFlagSize == "tiny" ? size.tiny : entryFlagSize == "small" ? size.small : entryFlagSize == "normal" ? size.normal : entryFlagSize == "large" ? size.large : size.huge

getEntry2FlagSize() =>
    entry2FlagSize == "tiny" ? size.tiny : entry2FlagSize == "small" ? size.small : entry2FlagSize == "normal" ? size.normal : entry2FlagSize == "large" ? size.large : size.huge

// ===== Pattern Detection =====
// Entry 1: Crosses EMA
bullishPattern1 = showBullishSignals and threeConsecutiveBullish() and bullishFVG() and candlesInteractWithEMA()
bearishPattern1 = showBearishSignals and threeConsecutiveBearish() and bearishFVG() and candlesInteractWithEMA()

// Entry 2: Does NOT cross EMA
bullishPattern2 = showBullishSignals and threeConsecutiveBullish() and bullishFVG() and candlesDoNotInteractWithEMA()
bearishPattern2 = showBearishSignals and threeConsecutiveBearish() and bearishFVG() and candlesDoNotInteractWithEMA()

// Engulfing patterns
isBullishEngulfing = showEngulfing and bullishEngulfing()
isBearishEngulfing = showEngulfing and bearishEngulfing()

// ===== Plot Signals (Arrows) =====
plotshape(bullishPattern1 or bullishPattern2, "Bullish Signal", getBullishShape(), location.belowbar, bullishSignalColor, size=size.small)
plotshape(bearishPattern1 or bearishPattern2, "Bearish Signal", getBearishShape(), location.abovebar, bearishSignalColor, size=size.small)

// ===== Entry Signal 1 (Crosses EMA) =====
if showEntrySignals and bullishPattern1
    // Entry flag
    label.new(bar_index, high, "ENTRY 1\nLONG\n(EMA Cross)", style=label.style_label_down, color=entryFlagColor, textcolor=color.white, size=getEntryFlagSize(), tooltip="Entry 1 (EMA Cross): " + str.tostring(close) + "\nSL: " + str.tostring(low[1]))
    
    // Entry line (close of 3rd candle)
    line.new(bar_index, close, bar_index + entryLineExtend, close, color=color.new(entryFlagColor, 30), width=2, style=line.style_solid)
    label.new(bar_index + entryLineExtend, close, "E1: " + str.tostring(close, "#.##"), style=label.style_label_left, color=color.new(entryFlagColor, 30), textcolor=color.white, size=size.small)
    
    if showStopLoss
        // Stop loss line (low of 2nd candle)
        line.new(bar_index, low[1], bar_index + entryLineExtend, low[1], color=color.new(color.red, 30), width=2, style=line.style_dashed)
        label.new(bar_index + entryLineExtend, low[1], "SL: " + str.tostring(low[1], "#.##"), style=label.style_label_left, color=color.new(color.red, 30), textcolor=color.white, size=size.small)

if showEntrySignals and bearishPattern1
    // Entry flag
    label.new(bar_index, low, "ENTRY 1\nSHORT\n(EMA Cross)", style=label.style_label_up, color=entryFlagColor, textcolor=color.white, size=getEntryFlagSize(), tooltip="Entry 1 (EMA Cross): " + str.tostring(close) + "\nSL: " + str.tostring(high[1]))
    
    // Entry line (close of 3rd candle)
    line.new(bar_index, close, bar_index + entryLineExtend, close, color=color.new(entryFlagColor, 30), width=2, style=line.style_solid)
    label.new(bar_index + entryLineExtend, close, "E1: " + str.tostring(close, "#.##"), style=label.style_label_left, color=color.new(entryFlagColor, 30), textcolor=color.white, size=size.small)
    
    if showStopLoss
        // Stop loss line (high of 2nd candle)
        line.new(bar_index, high[1], bar_index + entryLineExtend, high[1], color=color.new(color.red, 30), width=2, style=line.style_dashed)
        label.new(bar_index + entryLineExtend, high[1], "SL: " + str.tostring(high[1], "#.##"), style=label.style_label_left, color=color.new(color.red, 30), textcolor=color.white, size=size.small)

// ===== Entry Signal 2 (Does NOT Cross EMA) =====
if showEntrySignals2 and bullishPattern2
    // Entry flag
    label.new(bar_index, high, "ENTRY 2\nLONG\n(No EMA)", style=label.style_label_down, color=entry2FlagColor, textcolor=color.white, size=getEntry2FlagSize(), tooltip="Entry 2 (No EMA Cross): " + str.tostring(close) + "\nSL: " + str.tostring(low[1]))
    
    // Entry line (close of 3rd candle)
    line.new(bar_index, close, bar_index + entry2LineExtend, close, color=color.new(entry2FlagColor, 30), width=2, style=line.style_dotted)
    label.new(bar_index + entry2LineExtend, close, "E2: " + str.tostring(close, "#.##"), style=label.style_label_left, color=color.new(entry2FlagColor, 30), textcolor=color.white, size=size.small)
    
    if showStopLoss2
        // Stop loss line (low of 2nd candle)
        line.new(bar_index, low[1], bar_index + entry2LineExtend, low[1], color=color.new(color.orange, 30), width=2, style=line.style_dashed)
        label.new(bar_index + entry2LineExtend, low[1], "SL2: " + str.tostring(low[1], "#.##"), style=label.style_label_left, color=color.new(color.orange, 30), textcolor=color.white, size=size.small)

if showEntrySignals2 and bearishPattern2
    // Entry flag
    label.new(bar_index, low, "ENTRY 2\nSHORT\n(No EMA)", style=label.style_label_up, color=entry2FlagColor, textcolor=color.white, size=getEntry2FlagSize(), tooltip="Entry 2 (No EMA Cross): " + str.tostring(close) + "\nSL: " + str.tostring(high[1]))
    
    // Entry line (close of 3rd candle)
    line.new(bar_index, close, bar_index + entry2LineExtend, close, color=color.new(entry2FlagColor, 30), width=2, style=line.style_dotted)
    label.new(bar_index + entry2LineExtend, close, "E2: " + str.tostring(close, "#.##"), style=label.style_label_left, color=color.new(entry2FlagColor, 30), textcolor=color.white, size=size.small)
    
    if showStopLoss2
        // Stop loss line (high of 2nd candle)
        line.new(bar_index, high[1], bar_index + entry2LineExtend, high[1], color=color.new(color.orange, 30), width=2, style=line.style_dashed)
        label.new(bar_index + entry2LineExtend, high[1], "SL2: " + str.tostring(high[1], "#.##"), style=label.style_label_left, color=color.new(color.orange, 30), textcolor=color.white, size=size.small)

// ===== Plot Engulfing Candles (Labels Only) =====
labelSizeEngulfing = engulfingLabelSize == "tiny" ? size.tiny : engulfingLabelSize == "small" ? size.small : engulfingLabelSize == "normal" ? size.normal : size.large

if isBullishEngulfing
    label.new(bar_index, low, "BE", style=label.style_label_up, color=bullishEngulfingColor, textcolor=color.white, size=labelSizeEngulfing, tooltip="Bullish Engulfing")

if isBearishEngulfing
    label.new(bar_index, high, "BE", style=label.style_label_down, color=bearishEngulfingColor, textcolor=color.white, size=labelSizeEngulfing, tooltip="Bearish Engulfing")

// ===== Draw FVG Boxes (No Labels) =====
if showFVGBoxes and (bullishPattern1 or bullishPattern2)
    box.new(bar_index - 1, high[2], bar_index + fvgBoxExtension, low[0], border_color=color.new(color.green, 50), bgcolor=fvgBullishColor, border_width=1)

if showFVGBoxes and (bearishPattern1 or bearishPattern2)
    box.new(bar_index - 1, low[2], bar_index + fvgBoxExtension, high[0], border_color=color.new(color.red, 50), bgcolor=fvgBearishColor, border_width=1)

// ===== 5-Minute Support & Resistance with Nearest 5 Extension =====
if showSR
    [high5m, low5m] = request.security(syminfo.tickerid, "5", [high, low], lookahead=barmerge.lookahead_off)
    
    // Arrays to store support and resistance levels
    var array<float> supportLevels = array.new<float>()
    var array<float> resistanceLevels = array.new<float>()
    
    // Clear arrays on each bar
    array.clear(supportLevels)
    array.clear(resistanceLevels)
    
    // Collect all pivot points from history
    for i = srLookback to math.min(srHistoryBars, bar_index)
        pivotHigh = ta.pivothigh(high5m, srLookback, srLookback)[i - srLookback]
        pivotLow = ta.pivotlow(low5m, srLookback, srLookback)[i - srLookback]
        
        if not na(pivotHigh)
            array.push(resistanceLevels, pivotHigh)
        
        if not na(pivotLow)
            array.push(supportLevels, pivotLow)
    
    // Get current price
    currentPrice = close
    
    // Function to sort levels by distance from current price
    if showNearestOnly and array.size(supportLevels) > 0
        // Create arrays for distance calculations
        var array<float> supportDistances = array.new<float>()
        array.clear(supportDistances)
        
        // Calculate distances for support levels (below current price)
        for i = 0 to array.size(supportLevels) - 1
            level = array.get(supportLevels, i)
            if level < currentPrice
                distance = currentPrice - level
                array.push(supportDistances, distance)
            else
                array.push(supportDistances, 999999999.0)  // Exclude levels above price
        
        // Sort and get 5 nearest support levels
        for j = 0 to math.min(4, array.size(supportLevels) - 1)
            minDist = 999999999.0
            minIdx = 0
            
            for i = 0 to array.size(supportDistances) - 1
                if array.get(supportDistances, i) < minDist
                    minDist = array.get(supportDistances, i)
                    minIdx = i
            
            if minDist < 999999999.0
                supportLevel = array.get(supportLevels, minIdx)
                line.new(bar_index - srHistoryBars, supportLevel, bar_index + 500, supportLevel, color=supportColor, width=2, style=line.style_solid, extend=extend.right)
                label.new(bar_index - srHistoryBars + 10, supportLevel, "S", style=label.style_label_right, color=supportColor, textcolor=color.white, size=size.small)
                array.set(supportDistances, minIdx, 999999999.0)  // Mark as used
    
    if showNearestOnly and array.size(resistanceLevels) > 0
        // Create arrays for distance calculations
        var array<float> resistanceDistances = array.new<float>()
        array.clear(resistanceDistances)
        
        // Calculate distances for resistance levels (above current price)
        for i = 0 to array.size(resistanceLevels) - 1
            level = array.get(resistanceLevels, i)
            if level > currentPrice
                distance = level - currentPrice
                array.push(resistanceDistances, distance)
            else
                array.push(resistanceDistances, 999999999.0)  // Exclude levels below price
        
        // Sort and get 5 nearest resistance levels
        for j = 0 to math.min(4, array.size(resistanceLevels) - 1)
            minDist = 999999999.0
            minIdx = 0
            
            for i = 0 to array.size(resistanceDistances) - 1
                if array.get(resistanceDistances, i) < minDist
                    minDist = array.get(resistanceDistances, i)
                    minIdx = i
            
            if minDist < 999999999.0
                resistanceLevel = array.get(resistanceLevels, minIdx)
                line.new(bar_index - srHistoryBars, resistanceLevel, bar_index + 500, resistanceLevel, color=resistanceColor, width=2, style=line.style_solid, extend=extend.right)
                label.new(bar_index - srHistoryBars + 10, resistanceLevel, "R", style=label.style_label_right, color=resistanceColor, textcolor=color.white, size=size.small)
                array.set(resistanceDistances, minIdx, 999999999.0)  // Mark as used

// ===== Alerts =====
alertcondition(bullishPattern1, "Bullish Entry 1 (EMA Cross)", "LONG Entry 1: 3 Candle Bullish FVG crosses EMA")
alertcondition(bearishPattern1, "Bearish Entry 1 (EMA Cross)", "SHORT Entry 1: 3 Candle Bearish FVG crosses EMA")
alertcondition(bullishPattern2, "Bullish Entry 2 (No EMA)", "LONG Entry 2: 3 Candle Bullish FVG without EMA cross")
alertcondition(bearishPattern2, "Bearish Entry 2 (No EMA)", "SHORT Entry 2: 3 Candle Bearish FVG without EMA cross")
alertcondition(isBullishEngulfing, "Bullish Engulfing", "Bullish engulfing candle detected")
alertcondition(isBearishEngulfing, "Bearish Engulfing", "Bearish engulfing candle detected")